#include <algorithm>
#include <mutex>

#include "common/elements/element.h"
#include "common/more/string.h"

#include "item.h"

namespace Elements
{

Item::Item(const Item& other)
    : Element(other)
    , m_itemTypeId(other.m_itemTypeId)
    , m_parentId(other.m_parentId)
    , m_stateId(other.m_stateId)
    , m_phaseId(other.m_phaseId)
    , m_caption(other.m_caption)
    , m_description(other.m_description)
    , m_searchCaption(other.m_searchCaption)
    , m_searchDescription(other.m_searchDescription)
{
}

bool Item::isSame(Element* const other) const
{
    const auto otherElement = dynamic_cast<Item const*>(other);
    if (nullptr == otherElement)
        return false;

    return bool(
        m_id == otherElement->m_id
        && m_itemTypeId == otherElement->m_itemTypeId
        && m_parentId == otherElement->m_parentId
        && m_stateId == otherElement->m_stateId
        && m_phaseId == otherElement->m_phaseId
        && m_caption == otherElement->m_caption
        && m_description == otherElement->m_description
        && m_searchCaption == otherElement->m_searchCaption
        && m_searchDescription == otherElement->m_searchDescription
    );
}

Common::Json Item::toJson() const
{
    std::shared_lock locker(m_lock);
    Common::Json result;
    result["id"] = m_id;
    result["elementType"] = unsigned(elementType());
    result["itemTypeId"] = m_itemTypeId;
    result["parentId"] = m_parentId;
    result["stateId"] = m_stateId;
    result["phaseId"] = m_phaseId;
    result["caption"] = m_caption;
    result["description"] = m_description;
    result["searchCaption"] = m_searchCaption;
    result["searchDescription"] = m_searchDescription;
    return result;
}

void Item::fromJson(const Common::Json& json)
{
    std::shared_lock locker(m_lock);
    m_id = json["id"].get<unsigned>();
    m_itemTypeId = json["itemTypeId"].get<unsigned>();
    m_parentId = json["parentId"].get<unsigned>();
    m_stateId = json["stateId"].get<unsigned>();
    m_phaseId = json["phaseId"].get<unsigned>();
    m_caption = json["caption"].get<std::string>();
    m_description = json["description"].get<std::string>();
    m_searchCaption = json["searchCaption"].get<std::string>();
    m_searchDescription = json["searchDescription"].get<std::string>();
}

Element* Item::clone() const
{
    return new Item(*this);
}

ElementType Item::elementType() const
{
    return ElementType::Item;
}

unsigned Item::itemTypeId() const
{
    std::shared_lock locker(m_lock);
    return m_itemTypeId;
}

void Item::setItemTypeId(unsigned value)
{
    std::unique_lock locker(m_lock);
    m_itemTypeId = value;
}

unsigned Item::parentId() const
{
    std::shared_lock locker(m_lock);
    return m_parentId;
}

void Item::setParentId(unsigned value)
{
    std::unique_lock locker(m_lock);
    m_parentId = value;
}

unsigned Item::stateId() const
{
    std::shared_lock locker(m_lock);
    return m_stateId;
}

void Item::setStateId(unsigned value)
{
    std::unique_lock locker(m_lock);
    m_stateId = value;
}

unsigned Item::phaseId() const
{
    std::shared_lock locker(m_lock);
    return m_phaseId;
}

void Item::setPhaseId(unsigned value)
{
    std::unique_lock locker(m_lock);
    m_phaseId = value;
}

std::string Item::caption() const
{
    std::shared_lock locker(m_lock);
    return m_caption;
}

void Item::setCaption(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_caption = value;
    locker.unlock();
    setSearchCaption(value);
}

std::string Item::description() const
{
    std::shared_lock locker(m_lock);
    return m_description;
}

void Item::setDescription(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_description = value;
    locker.unlock();
    setSearchDescription(value);
}

std::string Item::searchCaption() const
{
    std::shared_lock locker(m_lock);
    return m_searchCaption;
}

void Item::setSearchCaption(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_searchCaption = Common::toLowerCase(value);
}

std::string Item::searchDescription() const
{
    std::shared_lock locker(m_lock);
    return m_searchDescription;
}

void Item::setSearchDescription(const std::string& value)
{
    std::unique_lock locker(m_lock);
    m_searchDescription = Common::toLowerCase(value);
}

} // namespace Elements
